#include "geomview.h"

#ifndef P_tmpdir
#define P_tmpdir "."
#endif

#define CMD_SIZE	65536
#define PATH_SIZE	4096

static char *GV_noface(gvctrl* ctrl);
static char* GV_faced(gvctrl* ctrl);
static int GV_coords(gvctrl* ctrl,char* F_coords);
static int __build_faces(gvctrl* ctrl,int tmpfd);
static void __print_face(gvctrl* ctrl,int v,int x,int size,int* prev,int tmpfd);
static int __find_face(gvctrl* ctrl,
		       int orig, int v,int w,
		       int* forbid,int* prev,int* curr,int* nxtcurr);
static void __print_offhead(gvctrl* ctrl,int nb_faces, int tmpfd);
static gvcolor* GV_createcolors(int nb);
static char* GV_colorize(gvctrl* ctrl,char* F_off,gvcolor* colors);


int GV_plotpart(char* F_graph,char* F_coords,char* F_where){
  PlotGraphType* graph;
  FILE* fp;
  char* fig;
  char* ext;
  gvctrl ctrl;
  gvcolor *colors;
  char F_off[CMD_SIZE];
  char* F_res;
  char cmd[CMD_SIZE];
  int i,nvtxs,nbpro;
  int* where;

  WARNING(((fp = fopen(F_graph,"r")) == NULL,"GV_plotgraph error code 1 : cannot open %s\n",F_graph),0);
  graph = PLIBG_Read(fp);
  fclose(fp);

  ctrl.g      = graph;
  ctrl.dim    = 0;
  ctrl.coords = NULL;
  ctrl.win    = NULL;

  nvtxs       = graph->nvtxs;
  where       = graph->pro;

  /* search off file if file finishing with .graph replace it with .off else add .off */

  strcpy(F_off,F_graph);      

  ext = strstr(F_off,".graph");
  if(ext != NULL)
    strcpy(ext,".off");
  else
    strcat(F_off,".off");
  
  if((fp = fopen(F_off,"r")) == NULL || fclose(fp) == EOF){
    /* off not found */    
        
    GV_coords(&ctrl,F_coords);

    //fig = GV_noface(&ctrl);
    fig = GV_faced(&ctrl);

    sprintf(cmd,"cp %s %s",fig,F_off);
    ERROR((system(cmd)!=0,"GV_plotgraph error code 2 : error in cp\n"));
    remove(fig);
    U_free("GV_plotgraph error code 3\n",&fig,LEND);
  }    

  /* read where */
  nbpro = 0;
  WARNING(((fp = fopen(F_where,"r")) == NULL,"GV_plotpart error code 3 : cannot open %s\n",F_where),0);
  for(i=0;i<nvtxs;i++){
    fscanf(fp,"%d",where + i);
    if(where[i] + 1 > nbpro)
      nbpro = where[i] + 1;
  }
  fclose(fp);

  colors = GV_createcolors(nbpro);
  F_res = GV_colorize(&ctrl,F_off,colors);

  ctrl.win = geomview_init();
   
  geomview_load(ctrl.win,F_res,GV_DEFAULT);
  
  getchar();
  getchar();
  
  geomview_close(ctrl.win);

  remove(F_res);
  U_free("GV_plot part free error 1\n",&colors,&F_res,LEND);
  return 1;  
}

char* GV_colorize(gvctrl* ctrl,char* F_off,gvcolor* colors){
  int i;
  char line[CMD_SIZE];
  char linecpy[CMD_SIZE];
  int tmpfd;
  char F_col[PATH_SIZE];
  char *F_tmp = U_malloc(PATH_SIZE,char,"GV_noface error code 1\n");
  FILE* fp;
  int linenb  = 0;
  int header  = 2;
  int coords;
  int nvtxs   = ctrl->g->nvtxs;
  int* where  = ctrl->g->pro;
  char* tok;
  int nbfaces = 0;
  int nblist,node,pro,ok;
  
  sprintf(F_col,"%s/geomview-XXXXXX", P_tmpdir);
  WARNING((((tmpfd=mkstemp(F_col))==-1),
	   "GV_colorize error code 1 : cannot create temporary file"),
	  NULL);
  WARNING(((fp = fopen(F_off,"r")) == NULL,"GV_colorize error code 1 : cannot open %s",F_off),NULL);
  
  coords = nvtxs;
  for(;;){
    do{
      fgets(line,CMD_SIZE,fp);
      linenb++;	
    }while(!feof(fp) && (line[0] == '#' || strcmp(line,"\n") == 0));
    
    if(feof(fp))
      break;

    /* skip header */
    if(header){
      header--;
      continue;
    }
    
    /* copy coords */
    if(coords){
      coords--;
      write(tmpfd, line, strlen(line));
      continue;
    }
    
    /* add faces that has all their vertices assigned to the same processor */
    strcpy(linecpy,line);
    pro = -1;
    ok  = 1;
    
    WARNING(((tok = strtok(linecpy," ")) == NULL,"GV_colorize error code 1  cannot read number of vertices in face on line %d\n",linenb),NULL);

    nblist = atoi(tok);
    
    for(i=0;i<nblist;i++){
      WARNING(((tok = strtok(NULL," ")) == NULL,"GV_colorize error code 1  cannot read vertices %d in face on line %d\n",i,linenb),NULL);
      node = atoi(tok);

      if(pro == -1)
	pro = where[node];
      if(pro != where[node]){
	ok = 0;
	break;
      }
    }
    if(ok){
      write(tmpfd, line, strlen(line) - 1);
      sprintf(line,"  %f %f %f %f\n",colors[pro].r,colors[pro].g,colors[pro].b,colors[pro].a);
      write(tmpfd, line, strlen(line));
      nbfaces++;
    }    
  }  

  fclose(fp);
  close(tmpfd);

  sprintf(F_tmp,"%s/geomview-XXXXXX", P_tmpdir);
  WARNING((((tmpfd=mkstemp(F_tmp))==-1),
	   "GV_colorize error code 1 : cannot create temporary file"),
	  NULL);
  sprintf(line,"OFF\n");
  write(tmpfd, line, strlen(line));
  sprintf(line,"%d %d %d\n",nvtxs,nbfaces,0);
  write(tmpfd, line, strlen(line));
  close(tmpfd);

  sprintf(line,"cat %s >> %s",F_col,F_tmp);
  
  ERROR((system(line)!=0,"GV_colorize error code 2 : error in cat\n"));
  remove(F_col);

  return F_tmp;
}
gvcolor* GV_createcolors(int nb){
  gvcolor* colors = U_malloc(nb,gvcolor,"GV_createcolors malloc error 1\n");
  double space = 59.99/nb;
  double pos   = 0.0;
  int intpos;
  double dbpos;
  
  int bucket,i;
  
  for(i=0;i<nb;i++){
    bucket = pos/10;
    intpos = (int)pos;
    dbpos  = pos - intpos;

    switch(bucket){
    case 0:
      colors[i].r = 1;
      colors[i].g = ((double)(intpos%10) + dbpos)/10;
      colors[i].b = 0;
      colors[i].a = 1;
      break;
    case 1:
      colors[i].r = (10 - (double)(intpos%10) + dbpos)/10;
      colors[i].g = 1;
      colors[i].b = 0;
      colors[i].a = 1;
      break;
    case 2:
      colors[i].r = 0;
      colors[i].g = 1;
      colors[i].b = ((double)(intpos%10) + dbpos)/10;
      colors[i].a = 1;
      break;
    case 3:
      colors[i].r = 0;
      colors[i].g = (10 - (double)(intpos%10) + dbpos)/10;
      colors[i].b = 1;
      colors[i].a = 1;
      break;
    case 4:
      colors[i].r = ((double)(intpos%10) + dbpos)/10;
      colors[i].g = 0;
      colors[i].b = 1;
      colors[i].a = 1;
      break;
    case 5:
      colors[i].r = 1;
      colors[i].g = 0;
      colors[i].b = (10 - (double)(intpos%10) + dbpos)/10;
      colors[i].a = 1;
      break;
    }    
    pos += space;
  }

  return colors;
}
int GV_plotgraph(char* F_graph,char* F_coords){
  PlotGraphType* graph;
  FILE* fp;
  char* fig;
  char* ext;
  gvctrl ctrl;
  char F_off[CMD_SIZE];
  char cmd[CMD_SIZE];

  ctrl.g      = NULL;
  ctrl.dim    = 0;
  ctrl.coords = NULL;
  ctrl.win    = NULL;

  /* search off file if file finishing with .graph replace it with .off else add .off */

  strcpy(F_off,F_graph);      

  ext = strstr(F_off,".graph");
  if(ext != NULL)
    strcpy(ext,".off");
  else
    strcat(F_off,".off");
  
  if((fp = fopen(F_off,"r")) == NULL || fclose(fp) == EOF){
    /* off not found */
    WARNING(((fp = fopen(F_graph,"r")) == NULL,"GV_plotgraph error code 1 : cannot open %s\n",F_graph),0);
    graph = PLIBG_Read(fp);
    fclose(fp);
    
    ctrl.g = graph;
    GV_coords(&ctrl,F_coords);

    fig = GV_noface(&ctrl);
    //fig = GV_faced(&ctrl);

    sprintf(cmd,"cp %s %s",fig,F_off);
    ERROR((system(cmd)!=0,"GV_plotgraph error code 2 : error in cp\n"));
    remove(fig);
    U_free("GV_plotgraph error code 3\n",&fig,LEND);
  }    

  ctrl.win = geomview_init();
   
  geomview_load(ctrl.win,F_off,GV_DEFAULT);
  
  getchar();
  getchar();
  
  geomview_close(ctrl.win);
  
  return 1;  
}

char *GV_noface(gvctrl* ctrl){
  int tmpfd;
  char *F_tmp = U_malloc(PATH_SIZE,char,"GV_noface error code 1\n");
  char line[CMD_SIZE];
  int v,w,i,j,jstart,jend;
  PlotGraphType *g = ctrl->g;

  int nedges  = g->nedges/2;
  int nvtxs   = g->nvtxs;
  int* adjidx = g->adjidx;
  int* adjncy = g->adjncy;
  gvpos* pos  = ctrl->coords;
  int dim     = ctrl->dim;

  sprintf(F_tmp,"%s/geomview-XXXXXX", P_tmpdir);
  WARNING((((tmpfd=mkstemp(F_tmp))==-1),
	   "GV_noface error code 1 : cannot create temporary file"),
	  NULL);

  sprintf(line,"VECT\n");
  write(tmpfd, line, strlen(line));

  sprintf(line,"%d %d %d\n",nedges,nedges*2,1);
  write(tmpfd, line, strlen(line));
  
  for(i=0;i<nedges;i++){
    sprintf(line,"2 ");
    write(tmpfd, line, strlen(line));
  }
  sprintf(line,"\n");
  write(tmpfd, line, strlen(line));

  sprintf(line,"1");
  write(tmpfd, line, strlen(line));

  for(i=1;i<nedges;i++){
    sprintf(line," 0");
    write(tmpfd, line, strlen(line));
  }
  sprintf(line,"\n");
  write(tmpfd, line, strlen(line));
  
  for(v=0;v<nvtxs;v++){
    jstart = adjidx[v];
    jend   = adjidx[v+1];

    for(j=jstart;j<jend;j++){
      w = adjncy[j];
      if(v<w){
	switch(dim){
	case 1:
	  sprintf(line,"%g %g %g  %g %g %g\n",pos[v].x,0.0,0.0,pos[w].x,0.0,0.0);
	  break;
	case 2:
	  sprintf(line,"%g %g %g  %g %g %g\n",pos[v].x,pos[v].y,0.0,pos[w].x,pos[w].y,0.0);
	  break;
	case 3:
	  sprintf(line,"%g %g %g  %g %g %g\n",pos[v].x,pos[v].y,pos[v].z,pos[w].x,pos[w].y,pos[w].z);
	  break;
	default:
	  WARNING((1,"GV_noface error code 2 : false dimension (%d)\n",dim),NULL);
	}
	write(tmpfd, line, strlen(line));
      }
    }
  }

  /* color */
  sprintf(line,"1 0 0 1\n");
  write(tmpfd, line, strlen(line));

  close(tmpfd);
  return F_tmp;
}

int GV_coords(gvctrl* ctrl,char* F_coords){
  int nvtxs = ctrl->g->nvtxs;
  gvpos *coords = ctrl->coords = U_malloc(nvtxs,gvpos,"GV_coords error code 1\n");
  char buffer[CMD_SIZE];
  int linenb = 1,dim,i;
  float dummy;
  FILE* fp;
  
  WARNING(((fp=fopen(F_coords,"r"))==NULL,"GV_coords error : cannot open coordinate file %s\n",F_coords),0);
  
  WARNING((fgets(buffer,CMD_SIZE,fp) == NULL,"GV_coords error : cannot read line %d\n",linenb),0);
  dim = ctrl->dim = sscanf(buffer,"%g %g %g",&dummy,&dummy,&dummy);
  rewind(fp);

  for(i=0;i<nvtxs;i++){
    WARNING((fgets(buffer,255,fp) == NULL,"GV_coords error : cannot read line %d\n",i+1),0);

    switch(dim){
    case 1:
      WARNING((sscanf(buffer,"%g",&(coords[i].x))!=1,"GV_coords error : line %d is not correct\n",i+1),0);
      break;
    case 2:
      WARNING((sscanf(buffer,"%g %g",&(coords[i].x),&(coords[i].y))!=2,"GV_coords error : line %d is not correct\n",i+1),0);
      break;
    case 3:
      WARNING((sscanf(buffer,"%g %g %g",&(coords[i].x),&(coords[i].y),&(coords[i].z))!=3,"GV_coords error : line %d is not correct\n",i+1),0);
      break;
    }
  }

  fclose(fp);
  return 1;
}

char* GV_faced(gvctrl* ctrl){
  char F_tmp[PATH_SIZE];
  char *F_off = U_malloc(PATH_SIZE,char,"GV_faced malloc error 1\n");
  int tmpfd, nb_faces;
  char line[CMD_SIZE];

  sprintf(F_tmp,"%s/geomview-XXXXXX", P_tmpdir);
  WARNING((((tmpfd=mkstemp(F_tmp))==-1),
	   "GV_faced error code 1 : cannot create temporary file"),
	  NULL);

  nb_faces = __build_faces(ctrl,tmpfd);
  close(tmpfd);

  sprintf(F_off,"%s/geomview-XXXXXX", P_tmpdir);
  WARNING((((tmpfd=mkstemp(F_off))==-1),
	   "GV_faced error code 1 : cannot create temporary file"),
	  NULL);

  __print_offhead(ctrl,nb_faces,tmpfd);
  close(tmpfd);

  sprintf(line,"cat %s >> %s",F_tmp,F_off);
  ERROR((system(line)!=0,"GV_faced error code 1 : error in cat\n"));
  remove(F_tmp);

  return F_off;
}

void __print_offhead(gvctrl* ctrl,int nb_faces, int tmpfd){
  char line[CMD_SIZE];
  PlotGraphType* g = ctrl->g;
  int nvtxs  = g->nvtxs;
  int nedges = g->nedges/2;
  int i,dim = ctrl->dim;
  gvpos* pos = ctrl->coords;

  sprintf(line,"OFF\n%d %d %d\n",nvtxs,nb_faces,nedges);
  write(tmpfd, line, strlen(line));
  
  for(i=0;i<nvtxs;i++){
    switch(dim){
    case 1:
      sprintf(line,"%g %g %g\n",pos[i].x,0.0,0.0);
      write(tmpfd, line, strlen(line));
      break;
    case 2:
      sprintf(line,"%g %g %g\n",pos[i].x,pos[i].y,0.0);
      write(tmpfd, line, strlen(line));
      break;
    case 3:
      sprintf(line,"%g %g %g\n",pos[i].x,pos[i].y,pos[i].z);
      write(tmpfd, line, strlen(line));      
      break;
    }
  }
}

int __build_faces(gvctrl* ctrl,int tmpfd){
  PlotGraphType* g = ctrl->g;
  int nvtxs   = g->nvtxs;
  int* adjidx = g->adjidx;
  int* adjncy = g->adjncy;

  int v,w,x,j,jstart,jend,k,l,size,nb_faces = 0;

  int* forbid    = U_mallocset(nvtxs,int,0 ,"__build_faces malloc error 1\n");
  int* tmpforbid = U_mallocset(nvtxs,int,0 ,"__build_faces malloc error 2\n");
  int* prev      = U_mallocset(nvtxs,int,-1,"__build_faces malloc error 3\n");
  int* curr      = U_mallocset(nvtxs,int,0 ,"__build_faces malloc error 4\n");
  int* nextcurr  = U_mallocset(nvtxs,int,0 ,"__build_faces malloc error 5\n");

  for(v=0;v<nvtxs;v++){
    printf("facing %d\n",v);
    tmpforbid[v] = forbid[v] = 1;
    
    jstart = adjidx[v];
    jend   = adjidx[v+1];

    for(j=jstart;j<jend;j++){
      w = adjncy[j];
      tmpforbid[w] = 1;
    }

    jstart = adjidx[v];
    jend   = adjidx[v+1];
    for(j=jstart;j<jend;j++){
      for(k=jstart;k<jend;k++){
	w = adjncy[j];
	x = adjncy[k];	
	/*printf("%d start %d end %d\n",v,w,x);*/

	if(k<=j)
	  continue;
	if(forbid[w] || forbid[x])
	  continue;
	
	memcpy(tmpforbid,forbid,nvtxs*sizeof(int));
	
	for(l=jstart;l<jend;l++){
	  tmpforbid[adjncy[l]] = 1;
	}

	/*printf("find face orig %d start %d end %d\n",v,w,x);*/
	size = __find_face(ctrl,v,w,x,tmpforbid,prev,curr,nextcurr);
	if(size){
	  __print_face(ctrl,v,x,size,prev,tmpfd);
	  nb_faces++;
	}
      }
    }    
  }
  return nb_faces;
}

void __print_face(gvctrl* ctrl,int v,int x,int size,int* prev,int tmpfd){
  char line[CMD_SIZE];

  sprintf(line,"%d %d",size,v);
  write(tmpfd, line, strlen(line));

  int pos = x;
  while(prev[pos] != v){
    sprintf(line," %d",pos);
    write(tmpfd, line, strlen(line));
    pos = prev[pos];
  }

  sprintf(line," %d\n",pos);
  write(tmpfd, line, strlen(line));

}

int __find_face(gvctrl* ctrl,
		int orig, int v,int w,
		int* forbid,int* prev,int* curr,int* nxtcurr){
  PlotGraphType* g = ctrl->g;
  int nvtxs   = g->nvtxs;
  int* adjidx = g->adjidx;
  int* adjncy = g->adjncy;
  int x,y,i,j,jstart,jend;
  int size = 3;
  int* tmp;

  for(i=0;i<nvtxs;i++){
    prev[i] = -1;
    curr[i] =  0;
  }

  prev[v] = orig;
  curr[v] = 1;

  for(;;){

    for(i=0;i<nvtxs;i++){
      nxtcurr[i] =  0;
    }

    for(x=0;x<nvtxs;x++){
      if(curr[x] == 0)
	continue;

      /*printf("search %d, on %d\n",w,x);
      {
	int j,jstart,jend;

	jstart = adjidx[w];
	jend   = adjidx[w+1];
	
	for(j=jstart;j<jend;j++){
	  printf("%d ",adjncy[j]);
	}
	printf("\n");
	}*/
      //getchar();
      
      jstart = adjidx[x];
      jend   = adjidx[x+1];
      
      for(j=jstart;j<jend;j++){
	y = adjncy[j];
	
	//printf("    adj %d (=? %d) forbid %d\n",y,w,forbid[y]);
	//getchar();	

	if(y == w){
	  prev[y] = x;
	  /*for(i=0;i<nvtxs;i++){
	    printf("%d => %d\n",i,prev[i]);	    
	    }*/
	  return size;
	}
	
	if(forbid[y])
	  continue;
	
	prev[y]    = x;
	forbid[y]  = 1;	
	nxtcurr[y] = 1;
      	
      }
      curr[x] = 0;
    }
    
    tmp     = curr;
    curr    = nxtcurr;
    nxtcurr = tmp;
    size++;
    if(size>GV_FACE)
      break;
  }

  return 0;
}
